﻿#include "encrypt.h"
#include "ui_encrypt.h"
#include <algorithm>
#include <QtCore>
#include <qmessagebox.h>
#include <QFileIconProvider>

EncryptDialog::EncryptDialog(MainWindow *parent, QString id):
    QDialog(parent),
    ui(new Ui::EncryptDialog)
{
    ui->setupUi(this);
    setLayout(ui->BaseLayout); //чтобы растянуть groupbox на весь диалог
	
	connect(ui->radioBase, SIGNAL(toggled(bool )), this, SLOT(radioSlot(bool)));
	connect(ui->radioFile, SIGNAL(toggled(bool)), this, SLOT(radioSlot(bool)));
	connect(ui->radioPassword, SIGNAL(toggled(bool)), this, SLOT(radioSlot(bool)));

	_parent = parent;
	


	if (_parent->_dbase == NULL) {
		ui->radioPassword->toggle();
	}
	else {
		ui->radioBase->toggle();
		_parent->loadKeys(*(ui->comboKeys), _idList);
		// если вызван из контекстного меню - выбрать ключ
		if (!id.isEmpty()) {
			ui->comboKeys->setCurrentIndex(_idList.indexOf(id));
			loadBaseModes(_idList.indexOf(id));
			connect(ui->comboKeys, SIGNAL(currentIndexChanged(int )), this, SLOT(loadBaseModes(int )));
		}
		else
			loadBaseModes(0);
	}
		
	connect(ui->buttonAdd, SIGNAL(clicked()), this, SLOT(loadFiles()));
	connect(ui->buttonDelete, SIGNAL(clicked()), this, SLOT(deleteFiles()));
	connect(ui->buttonEncrypt, SIGNAL(clicked()), this, SLOT(encrypt()));
	connect(ui->buttonDecrypt, SIGNAL(clicked()), this, SLOT(decrypt()));
	
	connect(ui->buttonFile, SIGNAL(clicked()), this, SLOT(moreFiles()));
	

	connect(ui->comboAlg, SIGNAL(currentIndexChanged(int )), this, SLOT(loadModes(int )));
	connect(ui->comboAlg3, SIGNAL(currentIndexChanged(int )), this, SLOT(loadModes(int )));
	
	
	_parent->loadCiphers(ui->comboAlg);
	_parent->loadCiphers(ui->comboAlg3);
	
}

void EncryptDialog::loadModes(int index) {
	QComboBox *box;
	QComboBox *sender = (QComboBox *)QObject::sender();
	if (sender == ui->comboAlg)
		box = ui->comboMode2;
	else if (sender == ui->comboAlg3)
		box = ui->comboMode3;
	else throw std::runtime_error("Wrong sender in loadModes");
	box->clear();

	ak_oid soid = ak_oids_by_name(sender->itemText(index).toStdString());
	for(int j = 0; j < ak_oids_count(); j++) {
	    ak_oid oid=ak_oids(j);
		
		if (oid.oid().find(soid.oid()) != std::string::npos && oid.oid() != soid.oid())
			box->addItem(QString::fromStdString(oid.name()));
	}
}

void EncryptDialog::radioSlot(bool checked) {
	ui->GroupBase->setEnabled(ui->radioBase->isChecked());
	ui->GroupPassword->setEnabled(ui->radioPassword->isChecked());
	ui->GroupFile->setEnabled(ui->radioFile->isChecked());
	if (ui->radioBase->isChecked() && _parent->_dbase == NULL)
		if (!_parent->openBase())
			ui->radioPassword->toggle();
		else {
			_parent->loadKeys(*(ui->comboKeys), _idList);
			loadBaseModes(0);
			connect(ui->comboKeys, SIGNAL(currentIndexChanged(int )), this, SLOT(loadBaseModes(int )));
		}
}

/*void EncryptDialog::loadAlgModes(int index) {
	ui->comboMode2->clear();
	for(int j = 0; j < ak_oids_count(); j++) {
	    ak_oid oid=ak_oids(j);
		ak_oid soid = ak_oids_by_name(ui->comboAlg->itemText(index).toStdString());
		if (oid.oid().find(soid.oid()) != std::string::npos && oid.oid() != soid.oid())
			ui->comboMode2->addItem(QString::fromStdString(oid.name()));
	}
}*/

void EncryptDialog::loadBaseModes(int index) {
	ui->comboModes->clear();
	for(int j = 0; j < ak_oids_count(); j++) {
	    ak_oid oid=ak_oids(j);
		std::string keyID = _idList[index].toStdString(), soid, ds;
		_parent->_dbase->info(keyID, soid, ds);
		if (oid.oid().find(soid) != std::string::npos && oid.oid() != soid)
			ui->comboModes->addItem(QString::fromStdString(oid.name()));
	}
}

void EncryptDialog::decrypt() {
	if (ui->FilesList->count() == 0) {
		_parent->showError(this, tr("Укажите файлы для расшифрования!"));
		return;
	}

	QStringList filesList;
	for (int i = 0; i < ui->FilesList->count(); i++)
		filesList.push_back(ui->FilesList->item(i)->text());
	try {
		QString keyFile = ui->editFile->text();
		dt = new DThread(_parent, filesList, _parent->_dbase, keyFile, ui->radioPassword->isChecked());
	} catch (PasswordCanceled e) {
		return;
	}
	QString title = tr("Расшифрование");
	pd = new ProgressDialog(_parent, filesList.count(), filesList[0], title);

	connect(dt, SIGNAL(jobFinished(QString )), pd, SLOT(stepProgress(QString )), Qt::QueuedConnection);
	connect(pd, SIGNAL(rejected()), dt, SLOT(cancel()), Qt::QueuedConnection);
	connect(dt, SIGNAL(jobAborted()), pd, SLOT(accept()), Qt::QueuedConnection);

	pd->show();
	dt->start();
}

void EncryptDialog::encrypt() {
	if (ui->FilesList->count() == 0) {
		_parent->showError(this, tr("Укажите файлы для шифрования!"));
		return;
	}


	QStringList filesList;
	for (int i = 0; i < ui->FilesList->count(); i++)
		filesList.push_back(ui->FilesList->item(i)->text());
	ak_symmetric_key* encryptionKey = NULL;
	std::string alg, mode;

	if (ui->radioPassword->isChecked()) {
		QString pass1 = _parent->getPassword(this, tr("Введите пароль на файл")), pass2 = _parent->getPassword(this, tr("Повторите пароль"));
		if (pass1 != pass2) {
			_parent->showError(this, tr("Пароли не совпадают!"));
			return;
		}
		alg = ui->comboAlg->currentText().toStdString();
		mode = ui->comboMode2->currentText().toStdString();
		try {
			encryptionKey  =
				ak_make_key_from_password( pass1.toStdString(), ak_oids_by_name(alg));
		} catch( ak_error e ) {
			_parent->showError(this, tr("Ошибка создания ключа: " ) + QString::fromStdString(e.message()));
            return;
		}
		_parent->wipeQString(pass1);
		_parent->wipeQString(pass2);
	}


	if(ui->radioFile->isChecked()) {
		QString passwd = _parent->getPassword(this);
		// получаем ключ доступа
		ak_master< ak_block_key> masterkey =ak_gost::new_key_from_password( passwd.toStdString() );
		ak_option_block_key ok( masterkey );
		//ak_wipe_string( passwd.toStdString() );

		alg = ui->comboAlg3->currentText().toStdString();
		mode = ui->comboMode3->currentText().toStdString();
	
		// создаем ключ шифрования
		ak_oid soid = ak_oids_by_name(alg);
		try {
			encryptionKey = ak_make_key_from_file( (ui->editFile->text()).toStdString(),
                                           soid, ok );
		} catch( ak_error e ) {
			if( e.message().find("CRC") != std::string::npos ) 
				_parent->showError(this, tr(" введен неверный пароль доступа\n")); 
		}
	}

	if (ui->radioBase->isChecked()) {
		QString key_id = _idList[ui->comboKeys->currentIndex()];
		if ((_pass = _parent->getPassword(this)).isEmpty()) 
			return;
		ak_master< ak_block_key> masterkey = ak_gost::new_key_from_password( _pass.toStdString() );
		ak_option_block_key ok( masterkey );
		_parent->wipeQString(_pass);
		encryptionKey = _parent->_dbase->symmetric_key( key_id.toStdString(), ok);
		alg = ak_oids_by_oid(encryptionKey->oid()).name();
		mode =  ui->comboModes->currentText().toStdString();
	}

	if (encryptionKey == NULL) {
		_parent->showError(this, tr("Не удалось создать ключ шифрования!"));
		return;
	}

	try {
		et = new EThread(_parent, filesList, encryptionKey, alg, mode);
	}
	catch( ak_error e ) {
		QString error;
        if( e.message().find("CRC") != std::string::npos ) 
			error = tr("Введен неверный пароль доступа!");
 	    else
			error = QString::fromStdString(e.message());
		_parent->showError(this, error);
		return;
    }
	QString title = tr("Шифрование");
	pd = new ProgressDialog(_parent, filesList.count(), filesList[0], title);

	connect(et, SIGNAL(jobFinished(QString )), pd, SLOT(stepProgress(QString )), Qt::QueuedConnection);
	connect(pd, SIGNAL(rejected()), et, SLOT(cancel()), Qt::QueuedConnection);
	connect(et, SIGNAL(jobAborted()), pd, SLOT(accept()), Qt::QueuedConnection);

	pd->show();
	et->start();
}

void EncryptDialog::loadFiles() {
	QFileDialog::Options options;
    QString selectedFilter;
	options |= QFileDialog::ShowDirsOnly;
	QStringList fileNames = QFileDialog::getOpenFileNames(this,
                                 tr("Добавить файлы"),
								 "","",&selectedFilter,
                                 options);
	// добавить только уникальные файлы
	for (int i = 0; i < ui->FilesList->count(); i++)
		fileNames.push_back(ui->FilesList->item(i)->text());
	fileNames.removeDuplicates();
	ui->FilesList->clear();
	QString fileName;
	foreach(fileName, fileNames) {
		QListWidgetItem *item = new QListWidgetItem(ui->FilesList);
		QFileInfo fi(fileName);
		// вытащить иконку из файла
		QFileIconProvider iconSource;
        QIcon icon = iconSource.icon(fi);
        item->setText(fileName);     
        item->setIcon(icon);	
	} 
}

void EncryptDialog::moreFiles() {
	
	QFileDialog::Options options;
	QFileDialog dialog;
    QString selectedFilter;
	options |= QFileDialog::ShowDirsOnly;
	QString fileName = QFileDialog::getOpenFileName(this,
                                 tr("Файл с ключом"),
								 "","",&selectedFilter,
                                 options);	

     ui->editFile->setText(fileName);

}


void EncryptDialog::deleteFiles() {
	
	qDeleteAll(ui->FilesList->selectedItems());
}
EncryptDialog::~EncryptDialog()
{


    delete ui;
}
